package at.codebase.web.util;

import java.util.Arrays;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import at.codebase.core.Settings;
import at.codebase.core.log.Log;
import at.codebase.db.dao.EUserDao;
import at.codebase.db.entities.EUser;
import at.codebase.web.util.URLParameters.ParameterDoesNotExistException;
import at.codebase.web.util.i18n.I18NLocale;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

/**
 * This class is used to create RequestInformation objects out of
 * ServletRequests.
 * 
 * @author Lukas Pfeifhofer <lukas.pfeifhofer@devlabs.pro>
 * 
 */
public class LocalRequest {

	/**
	 * Creates a RequestInformation from the given ServletRequest. TODO:
	 * Implement some database requests to get the language or some other
	 * important informations of the current user... Also a ArgumentParser would
	 * be nice!
	 * 
	 * 
	 * @param req
	 * @return
	 */
	public static RequestInformation create(HttpServletRequest req) {
		RequestInformation reqInfo = new RequestInformation();

		UserService userService = UserServiceFactory.getUserService();
		HttpSession session = req.getSession();

		// URL parameters
		reqInfo.parameters = URLParameters.create(req);

		// User
		if (userService.isUserLoggedIn()) {
			User googleUser = userService.getCurrentUser();
			EUser userEntity = EUserDao.getUserByGoogleId(googleUser.getUserId());

			if(Settings.ALLOW_DEMO_ACCOUNT_LOGIN){
				EUser tempUser = EUserDao.getUserByMail(googleUser.getEmail());
				if(tempUser != null){
					if(tempUser.getGoogleUserData().getAuthDomain().equals("example.com")){
						userEntity = tempUser;
					}
				}
			}
			
			// New user logged in
			if (userEntity == null) {
				userEntity = EUser.createUser(googleUser);
				// System.out.println("Create new user... (id="+userEntity.getId()+")");
				if (session.getAttribute("locale") != null) {
					userEntity.setLocale((String) session.getAttribute("locale"));
				} else {
					userEntity.setLocale(req.getLocale().getISO3Language());
				}
				
				if (userService.isUserAdmin()
						|| Arrays.asList(Settings.ADMIN_ACCOUNT_MAILS)
								.contains(
										userEntity.getGoogleUserData()
												.getEmail())) {
					userEntity.setAdmin(true);
				}
				
				//Dublicated Usernames
				while (EUserDao.duplicateUsername(userEntity.getUsername())) {
					Random random = new Random();
					userEntity.setUsername(userEntity.getUsername()
					+ (random.nextInt(50) + 50));
				}
				//String username = EUserDao.getDuplicateSafeUsername(userEntity.getUsername());
				
				EUserDao.saveUser(userEntity);
				Log.logUser(userEntity.getId(),
						"User (userid=" + userEntity.getId() + ", googleid="
								+ userService.getCurrentUser().getUserId()
								+ ") has been created");
			}

			reqInfo.user = userEntity;

		}

		// Scan for locale change
		if (reqInfo.parameters.isExisting("locale")) {
			try {
				String langName = reqInfo.parameters.getString("locale");
				// Check if its a legal existing language
				if (Arrays.asList(Settings.Locales.all).contains(
						new I18NLocale(langName))) {
					if (userService.isUserLoggedIn()) {
						reqInfo.user.setLocale(langName);
						EUserDao.saveUser(reqInfo.user);
					} else {
						session.setAttribute("locale", langName);
					}
				}
			} catch (ParameterDoesNotExistException e) {
				// Just ignore...
			}
		}

		// Load user locale
		if (userService.isUserLoggedIn()) {
			reqInfo.userLocale = new I18NLocale(reqInfo.getUser().getLocale());
		} else {
			if (session.getAttribute("locale") != null) {
				reqInfo.userLocale = new I18NLocale(
						(String) session.getAttribute("locale"));
			} else {
				reqInfo.userLocale = new I18NLocale(req.getLocale()
						.getISO3Language());
			}
		}

		// Absolute Path
		reqInfo.requestUrl = req.getRequestURL().toString()
				+ ((req.getQueryString() != null) ? "?" + req.getQueryString()
						: "");
		
		reqInfo.hostUrl = req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort();
		//reqInfo.hostUrl = req.getMethod()+req.getServerName()+req.getServerPort()+"-"+req.getLocalAddr()+"-"+req.getContextPath()+"-"+req.getContextPath()+"-"+req.getScheme();

		// Check if the user is inactive
		// If the user is not active he will be handled as anonymous user
		// He will be informed by the MainTemplate about his state
		if (reqInfo.user != null && (!reqInfo.getUser().isActive())
				&& (!reqInfo.getUser().isAdmin())) {
			reqInfo.user = null;
		}

		reqInfo.referrer = req.getHeader("referer");

		return reqInfo;
	}

	/**
	 * This class holds some RequestInformation. For example, it should be used
	 * to get a fast access to Session Variables or User Information. It will be
	 * created by the LocalRequest class.
	 * 
	 * @author Lukas Pfeifhofer <lukas.pfeifhofer@devlabs.pro>
	 * 
	 */
	public static class RequestInformation {

		private String requestUrl;
		private String hostUrl;
		private URLParameters parameters;

		private I18NLocale userLocale;
		private EUser user;

		String referrer;

		public I18NLocale getLocale() {
			return userLocale;
		}

		public String getRequestUrl() {
			return requestUrl;
		}
		
		public String getHostUrl(){
			return hostUrl;
		}

		public I18NLocale getUserLocale() {
			return userLocale;
		}

		public boolean isUserLoggedIn() {
			return (user != null);
		}

		public EUser getUser() {
			return user;
		}

		public URLParameters getParameters() {
			return parameters;
		}

		public String getReferrer() {
			return referrer;
		}

	}

}
